#ifndef __QUEUE_H__
#define __QUEUE_H__

#include "libs/lib.h"
#include "libs/types.h"
#include "kernel/log/log.h"

template<typename T>
class Queue
{
private:
    /* data */
public:

    List head;
    List* tail;
    List* pre; 
    int64_t count;
    Queue(/* args */);
    ~Queue();
    T* pop();
    void push(T* node);
    void push(T* node,int (*)(T*,T*));
    int isEmpty();
    void del(T* node);
    T* get();
    T* get(T* t,int(*)(T*,T*));
};





template<typename T>
Queue<T>::Queue(/* args */)
{
    list_init(&head);
    count == 0;
    tail = &head;
    pre = &head;
}
template<typename T>
Queue<T>::~Queue()
{
    
}

template<typename T>
T* Queue<T>::pop(){

    if(!count){
        LOG_ERROR("queque is null,can not pop!\n");
        return NULL;
    }
    list_del(pre);
    count--;
    if(!count)
        tail = &head;
    List* temp = pre;
    T* data = temp->data;
    delete temp;
    pre = head.next;
    return data;

}

template<typename T>
void Queue<T>::push(T* node){
    List* temp= new List();
    
    list_init(temp);
    temp->data = node;


    list_add_to_behind(tail,temp);


    if(!count)
        pre = head.next;

    count++;
    tail = temp;

}

template<typename T>
void Queue<T>::push(T* node,int (*compare)(T*,T*)){

   

    if(isEmpty()){
        push(node);
        return;
    }
    
    List* temp = pre;
    
    do{
        
        if(compare(node,temp->data))
        {  
            break;
        }
            
        temp = temp->next;
       
    }while(temp != &head);

    if(temp == &head){

        push(node);
        return;
    }
    List* te = new List();
    list_init(te);
    te->data = node;
    list_add_to_before(temp,te);
    count++;

    if(temp == pre){     
        pre = head.next;
    }

}



template<typename T>
int Queue<T>::isEmpty(){


    int ret = list_is_empty(&head);
    
    return ret;
}


template<typename T>
void Queue<T>::del(T* node){

    List* temp = pre;

    do{
        if(temp->data == node)
            break;
        temp = temp->next;
    }while(temp != &head);

    if(temp == pre){
        pop();
        return;
    }

    if(temp == tail){

        tail = tail->prev;

    }

    if(temp == &head){
        return;
    }

    list_del(temp);
    count--;
    delete temp;
}
template<typename T>
 T* Queue<T>::get(){

    
    return pre->data;

 }




template<typename T>
T* Queue<T>::get(T* t,int(searchTo)(T*,T*))
{
    List* temp = pre;
    do{

        if(searchTo(temp->data,t))
            return temp->data;

        temp = temp->next;

    }while(temp != &head);
    
    return NULL;
}




#endif

